package com.rojored.layouts
{

import flash.events.Event;
import flash.utils.getQualifiedClassName;
import mx.core.ILayoutElement;
import mx.logging.ILogger;
import mx.logging.Log;
import spark.layouts.supportClasses.LayoutBase;

/**
 *  Horizontal flow layout.
 */
public class FlowLayout extends LayoutBase
{

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor
     */
    public function FlowLayout()
    {
        super();
    }

    //--------------------------------------
    // horizontalGap
    //--------------------------------------

    /**
     *  @private
     *  Storage for the horizontalGap property
     */
    private var _horizontalGap:Number = 5;

    /**
     *  @private
     */
    private var horizontalGapChanged:Boolean;

    [Bindable("horizontalGapChanged")]

    /**
     *  Horizontal separation between elements
     */
    public function get horizontalGap():Number
    {
        return _horizontalGap;
    }

    /**
     *  @private
     */
    public function set horizontalGap(value:Number):void
    {
        if (_horizontalGap == value)
            return;

        _horizontalGap = value;
        horizontalGapChanged = true;
        target.invalidateDisplayList();
        target.invalidateSize();
        dispatchEvent(new Event("horizontalGapChanged"));
    }

    //--------------------------------------
    // verticalGap
    //--------------------------------------

    /**
     *  @private
     *  Storage for the verticalGap property
     */
    private var _verticalGap:Number = 3;

    /**
     *  @private
     */
    private var verticalGapChanged:Boolean;

    [Bindable("verticalGapChanged")]

    /**
     *  Vertical gap between rows.
     */
    public function get verticalGap():Number
    {
        return _verticalGap;
    }

    /**
     *  @private
     */
    public function set verticalGap(value:Number):void
    {
        if (_verticalGap == value)
            return;

        _verticalGap = value;
        verticalGapChanged = true;
        target.invalidateDisplayList();
        target.invalidateSize();
        dispatchEvent(new Event("verticalGapChanged"));
    }

    //--------------------------------------------------------------------------
    //
    //  Overridden methods: LayoutBase
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     */
    override public function updateDisplayList(width:Number,
                                               height:Number):void
    {
        var x:Number = 0;
        var y:Number = 0;
        var maxWidth:Number = 0;
        var maxHeight:Number = 0;
        var maxRowHeight:Number = 0;
        var elementWidth:Number;
        var elementHeight:Number;
        var n:int = target.numElements;
        for (var i:int = 0; i < n; i++)
        {
            var element:ILayoutElement = useVirtualLayout ?
                target.getVirtualElementAt(i) :
                target.getElementAt(i);

            element.setLayoutBoundsSize(NaN, NaN);
            elementWidth = element.getPreferredBoundsWidth();
            elementHeight = element.getPreferredBoundsHeight();

            if (x + elementWidth > width)
            {
                x = 0;
                y += maxRowHeight + verticalGap;
                maxRowHeight = elementHeight;
            }
            else
            {
                maxRowHeight = Math.max(maxRowHeight, elementHeight);
            }

            element.setLayoutBoundsPosition(x, y);

            maxHeight = Math.max(maxHeight, y + elementHeight);
            maxWidth = Math.max(maxWidth, x + elementWidth);

            x += elementWidth + horizontalGap;
        }
        target.setContentSize(maxWidth, maxHeight);
    }

    /**
     *  @private
     */
    override public function measure():void
    {

        var element:ILayoutElement;
        var numElements:int = target.numElements;
        var x:Number = 0;
        var y:Number = 0;
        var maxHeight:Number = 0;
        var maxWidth:Number;
        var elementWidth:Number;
        var elementHeight:Number;
        var maxRowHeight:Number = 0;

        var constrainedWidth:Number =
            (!isNaN(target.percentWidth) || !isNaN(target.explicitWidth)) ?
                target.width : NaN;

        for (var i:int = 0; i < numElements; i++)
        {
            element = target.getElementAt(i) || typicalLayoutElement;
            if (!element.includeInLayout)
                continue;

            elementWidth = element.getPreferredBoundsWidth();
            elementHeight = element.getLayoutBoundsHeight();

            if (isNaN(constrainedWidth))
            {
                maxHeight = Math.max(element.getPreferredBoundsHeight(),
                    maxHeight);

                maxWidth = x + elementWidth;
                x += elementWidth + horizontalGap;
            }
            else
            {
                if (x + elementWidth > constrainedWidth)
                {
                    x = 0;
                    y += maxRowHeight + verticalGap;
                    maxRowHeight = elementHeight;
                }
                else
                {
                    maxRowHeight = Math.max(maxRowHeight, elementHeight);
                }
                maxHeight = Math.max(maxHeight, y + elementHeight);
                maxWidth = Math.max(maxWidth, x + elementWidth);
                x += elementWidth + horizontalGap;
            }
        }

        target.measuredWidth = maxWidth;
        target.measuredHeight = maxHeight;
        target.measuredMinWidth = maxWidth;
        target.measuredMinHeight = maxHeight;
    }
}
}
